/*
 * 描述： <描述>
 * 修改人： rain
 * 修改时间： 2016年9月29日
 * 项目： rainhy-auth
 */
package com.rainhy.auth.context;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import com.rainhy.core.util.AssertUtils;

/**
 * 权限 session 容器
 * 
 * @author rain
 * @version [版本号, 2016年9月29日]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public class AuthSessionContext {
    
    /** session中当前登录人员拥有的权限引用项的MultiValueMap */
    public final static String SESSION_KEY_CURRENT_OPERATOR_AUTHREF_MULTIVALUEMAP = "rainhy.auth.AuthSessionContext.CurrentOperatorAuthrefMultivaluemap";
    
    /** session中当前登录人员的id,作为权限容器存在 */
    public final static String SESSION_KEY_CURRENT_OPERATOR_ID = "rainhy.auth.AuthSessionContext.CurrentOperatorId";
    //    
    //    /** session中当前登录人员的id,作为权限容器存在 */
    //    public final static String DATAMAP_KEY_QUERY_AUTH_MAP = "query_auth_map";
    //    
    //    /** session中当前登录人员的id,作为权限容器存在 */
    //    public final static String DATAMAP_KEY_IS_QUERY_BY_AUTH = "is_query_by_auth";
    
    /**
     * 线程变量:当前会话容器<br/>
     * 获取到该容器后可以<br/>
     * 获取当前回话的session从而获取到相应的权限列表
     */
    private static ThreadLocal<AuthSessionContext> currentSessionContext = new ThreadLocal<AuthSessionContext>() {
        @Override
        protected AuthSessionContext initialValue() {
            return new AuthSessionContext();
        }
    };
    
    /**
     * 将当前会话绑定到线程中
     * 
     * @param request
     * @param response [参数说明]
     * 
     * @return void [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public static void bindCurrentSessionToThread(HttpServletRequest request, HttpServletResponse response) {
        //绑定线程前先remove一次，以保证不会残留上一次的会话，虽然不是特别需要，也不会占用太多资源
        currentSessionContext.remove();
        //将当前会话绑定到现成中
        currentSessionContext.get().install(request, response);
    }
    
    /**
     * 
     * 从session中根据权限key获取权限项引用集合
     *
     * @param authItemKey 权限 key
     * 
     * @return List<AuthItemRef> key 对应的权限引用集合
     * @throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     * @version [版本号, 2016年9月30日]
     * @author rain
     */
    @SuppressWarnings("unchecked")
    public static List<AuthItemRef> getAuthRefsFromSession(String authItemKey) {
        HttpSession session = currentSessionContext.get().getSession();
        MultiValueMap<String, AuthItemRef> authItemRefMapping = (MultiValueMap<String, AuthItemRef>) session.getAttribute(SESSION_KEY_CURRENT_OPERATOR_AUTHREF_MULTIVALUEMAP);
        if (MapUtils.isNotEmpty(authItemRefMapping)) {
            return authItemRefMapping.get(authItemKey);
        }
        return null;
    }
    
    /**
     * 获取当前线程中的会话
     * 
     * @return [参数说明]
     * 
     * @return CurrentSessionContext [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public static AuthSessionContext getCurrentSessionContext() {
        return currentSessionContext.get();
    }
    
    /** 从当前会话中获取当前操作员的id */
    public static String getOperatorIdFromSession() {
        HttpSession session = currentSessionContext.get().getSession();
        String operatorId = (String) session.getAttribute(SESSION_KEY_CURRENT_OPERATOR_ID);
        return operatorId;
    }
    
    /**
     * 
     * 将当前操作人员的权限引用放入session中<br>
     *
     * @param authItemRefList
     * 
     * @return void [返回类型说明]
     * @throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     * @version [版本号, 2016年9月30日]
     * @author rain
     */
    public static void putAuthRefsToSession(List<AuthItemRef> authItemRefList) {
        MultiValueMap<String, AuthItemRef> authItemRefMap = new LinkedMultiValueMap<String, AuthItemRef>();
        //如果当前不存在会话，者直接跳过该逻辑
        if (CollectionUtils.isNotEmpty(authItemRefList)) {
            for (AuthItemRef refTemp : authItemRefList) {
                authItemRefMap.add(refTemp.getAuthItem().getKey(), refTemp);
            }
        }
        //将权限压入当前会话中,如果当前人员不含有权限，也会压入一个空的权限引用map
        HttpSession session = currentSessionContext.get().getSession();
        session.setAttribute(SESSION_KEY_CURRENT_OPERATOR_AUTHREF_MULTIVALUEMAP, authItemRefMap);
    }
    
    /** 将操作员的id放入session中 */
    public static void putOperatorIdToSession(String operatorId) {
        AssertUtils.notEmpty(operatorId, "操作员 id 不能为空");
        HttpSession session = currentSessionContext.get().getSession();
        session.setAttribute(SESSION_KEY_CURRENT_OPERATOR_ID, operatorId);
    }
    
    /**
     * 从当前线程中移除当前会话
     * 
     * @return void [返回类型说明]
     * @throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     * @version [版本号, 2016年9月29日]
     * @author rain
     */
    public static void removeCurrentSessionFromThread() {
        currentSessionContext.get().uninstall();
        currentSessionContext.remove();
    }
    
    /** 当前请求 */
    private HttpServletRequest request;
    
    /** 返回的response */
    private HttpServletResponse response;
    
    /** 当前请求的会话 */
    private HttpSession session;
    
    //    /**
    //     * @return 返回 dataMap
    //     */
    //    public Map<String, Object> getDataMap() {
    //        return dataMap;
    //    }
    //    
    //    /**
    //     * @return 返回 dataMap
    //     */
    //    public Object getAttributeFromDataMap(String key) {
    //        AssertUtils.notEmpty(key, "key is empty.");
    //        Object obj = this.dataMap.get(key);
    //        return obj;
    //    }
    //    
    //    /**
    //     * 将属性设置入DataMap中<br/>
    //     * <功能详细描述>
    //     * 
    //     * @param key
    //     * @param obj [参数说明]
    //     * 
    //     * @return void [返回类型说明]
    //     * @exception throws [异常类型] [异常说明]
    //     * @see [类、类#方法、类#成员]
    //     */
    //    public void setAttributeToDataMap(String key, Object obj) {
    //        AssertUtils.notEmpty(key, "key is empty.");
    //        AssertUtils.notNull(obj, "obj is null.");
    //        this.dataMap.put(key, obj);
    //    }
    
    //    /**
    //     * @return 返回 dataMap
    //     */
    //    @SuppressWarnings("unchecked")
    //    public <T> T getAttributeFromDataMap(String key, Class<T> type) {
    //        AssertUtils.notEmpty(key, "key is empty.");
    //        AssertUtils.notNull(type, "type is null.");
    //        if (!this.dataMap.containsKey(key)) {
    //            return null;
    //        }
    //        T res = null;
    //        Object obj = this.dataMap.get(key);
    //        if (type.isInstance(obj)) {
    //            res = (T) obj;
    //        }
    //        return res;
    //    }
    
    //    /**
    //     * 从CurrentSessionContext获取queryAuthMap 如果在获取过程中发现对应的Map不存在则自动创建 <功能详细描述>
    //     * 
    //     * @return [参数说明]
    //     * 
    //     * @return Map<String,String> [返回类型说明]
    //     * @exception throws [异常类型] [异常说明]
    //     * @see [类、类#方法、类#成员]
    //     */
    //    private static Map<String, String> getQueryAuthMapFromCurrentSessionContext() {
    //        @SuppressWarnings("unchecked")
    //        Map<String, String> queryAuthMap = currentSessionContext.get()
    //                .getAttributeFromDataMap(DATAMAP_KEY_QUERY_AUTH_MAP, Map.class);
    //        if (queryAuthMap == null) {
    //            queryAuthMap = new HashMap<String, String>();
    //            currentSessionContext.get()
    //                    .setAttributeToDataMap(DATAMAP_KEY_QUERY_AUTH_MAP,
    //                            queryAuthMap);
    //        }
    //        return queryAuthMap;
    //    }
    
    //    /**
    //     * 将操作员的id放入session中 <功能详细描述>
    //     * 
    //     * @param operatorId [参数说明]
    //     * 
    //     * @return void [返回类型说明]
    //     * @exception throws [异常类型] [异常说明]
    //     * @see [类、类#方法、类#成员]
    //     */
    //    public static void putToQueryAuthMap(String propertyName, String authKey) {
    //        AssertUtils.notEmpty(propertyName, "propertyName is empty.");
    //        AssertUtils.notEmpty(authKey, "authKey is empty.");
    //        
    //        Map<String, String> queryAuthMap = getQueryAuthMapFromCurrentSessionContext();
    //        
    //        queryAuthMap.put(propertyName, authKey);
    //    }
    
    //    /**
    //     * 获取查询权限集合<br/>
    //     * <功能详细描述>
    //     * 
    //     * @return [参数说明]
    //     * 
    //     * @return Set<String> [返回类型说明]
    //     * @exception throws [异常类型] [异常说明]
    //     * @see [类、类#方法、类#成员]
    //     */
    //    public static Map<String, String> getQueryAuthMap() {
    //        Map<String, String> queryAuthMap = getQueryAuthMapFromCurrentSessionContext();
    //        return queryAuthMap;
    //    }
    
    //    /**
    //     * 获取查询权限集合<br/>
    //     * <功能详细描述>
    //     * 
    //     * @return [参数说明]
    //     * 
    //     * @return Set<String> [返回类型说明]
    //     * @exception throws [异常类型] [异常说明]
    //     * @see [类、类#方法、类#成员]
    //     */
    //    public static boolean isContainsInQueryAuthMap(String propertyName) {
    //        AssertUtils.notEmpty(propertyName, "propertyName is empty.");
    //        
    //        Map<String, String> queryAuthMap = getQueryAuthMapFromCurrentSessionContext();
    //        return queryAuthMap.containsKey(propertyName)
    //                && !StringUtils.isEmpty(queryAuthMap.get(propertyName));
    //    }
    
    //    /**
    //     * 从当前线程变量中查询权限映射中取得指定属性值对应的权限key<br/>
    //     * <功能详细描述>
    //     * 
    //     * @param propertyName
    //     * @return [参数说明]
    //     * 
    //     * @return String [返回类型说明]
    //     * @exception throws [异常类型] [异常说明]
    //     * @see [类、类#方法、类#成员]
    //     */
    //    public static String getAuthKeyFromQueryAuthMap(String propertyName) {
    //        AssertUtils.notEmpty(propertyName, "propertyName is empty.");
    //        
    //        Map<String, String> queryAuthMap = getQueryAuthMapFromCurrentSessionContext();
    //        
    //        String resAuthKey = queryAuthMap.get(propertyName);
    //        return resAuthKey;
    //    }
    
    //    /**
    //     * 清空当前查询权限映射中的所有设置<br/>
    //     * <功能详细描述> [参数说明]
    //     * 
    //     * @return void [返回类型说明]
    //     * @exception throws [异常类型] [异常说明]
    //     * @see [类、类#方法、类#成员]
    //     */
    //    public static void clearQueryAuthMap() {
    //        Map<String, String> queryAuthMap = getQueryAuthMapFromCurrentSessionContext();
    //        queryAuthMap.clear();
    //    }
    
    /** 数据映射Map方便携带数据 */
    private final Map<String, Object> dataMap = new HashMap<String, Object>();
    
    /** 是否已经初始化 session */
    private boolean isInitSession = false;
    
    /** HttpServletRequest */
    public HttpServletRequest getRequest() {
        AssertUtils.isTrue(isInitSession, "请调用install方法初始化 HttpServletRequest");
        return request;
    }
    
    //    /**
    //     * 从session中获取权限集合<br/>
    //     * 1、当前如果不存在会话，者返回null <功能详细描述>
    //     * 
    //     * @return [参数说明]
    //     * 
    //     * @return List<AuthItemRef> [返回类型说明]
    //     * @exception throws [异常类型] [异常说明]
    //     * @see [类、类#方法、类#成员]
    //     */
    //    public static MultiValueMap<String, AuthItemRef> getAuthRefMultiValueMapFromSession() {
    //        @SuppressWarnings("unchecked")
    //        MultiValueMap<String, AuthItemRef> authItemRefMap = (MultiValueMap<String, AuthItemRef>) currentSessionContext.get()
    //                .getSession()
    //                .getAttribute(SESSION_KEY_CURRENT_OPERATOR_AUTHREF_MULTIVALUEMAP);
    //        return authItemRefMap == null ? new LinkedMultiValueMap<String, AuthItemRef>() : authItemRefMap;
    //    }
    
    /** HttpServletResponse */
    public HttpServletResponse getResponse() {
        AssertUtils.isTrue(isInitSession, "请调用install方法初始化 HttpServletResponse");
        return response;
    }
    
    //    /**
    //     * 获取当前所有权限引用对应的权限项列表 <功能详细描述>
    //     * 
    //     * @return [参数说明]
    //     * 
    //     * @return List<AuthItem> [返回类型说明]
    //     * @exception throws [异常类型] [异常说明]
    //     * @see [类、类#方法、类#成员]
    //     */
    //    public static List<AuthItem> getAuthItemListDependAuthRefOfSession() {
    //        Map<String, AuthItem> authItemMapping = AuthContext.getContext().getAuthItemMapping();
    //        
    //        List<AuthItem> authItemList = new ArrayList<AuthItem>();
    //        MultiValueMap<String, AuthItemRef> authRefMulMap = getAuthRefMultiValueMapFromSession();
    //        for (String authIdTemp : authRefMulMap.keySet()) {
    //            if (!authItemMapping.containsKey(authIdTemp)) {
    //                continue;
    //            }
    //            authItemList.add(authItemMapping.get(authIdTemp));
    //        }
    //        return authItemList;
    //    }
    
    //    /**
    //     * 根据父级权限id获取当前人员拥有的权限权限项列表 <功能详细描述>
    //     * 
    //     * @param parentId
    //     * @return [参数说明]
    //     * 
    //     * @return List<AuthItem> [返回类型说明]
    //     * @exception throws [异常类型] [异常说明]
    //     * @see [类、类#方法、类#成员]
    //     */
    //    public static List<AuthItem> getAuthItemListByParentIdFromSession(
    //            String parentId) {
    //        AssertUtils.notEmpty(parentId, "parentId is empty.");
    //        
    //        Map<String, AuthItem> authItemMapping = AuthContext.getContext().getAuthItemMapping();
    //        
    //        List<AuthItem> resList = new ArrayList<AuthItem>();
    //        MultiValueMap<String, AuthItemRef> authRefMulMap = getAuthRefMultiValueMapFromSession();
    //        for (String authIdTemp : authRefMulMap.keySet()) {
    //            if (!authItemMapping.containsKey(authIdTemp)) {
    //                continue;
    //            }
    //            AuthItem authItemTemp = authItemMapping.get(authIdTemp);
    //            if (parentId.equals(authItemTemp.getParentId())) {
    //                resList.add(authItemTemp);
    //            }
    //        }
    //        return resList;
    //    }
    
    //    /**
    //     * 根据父级权限id以及权限类型获取当前人员拥有的权限权限项列表 <功能详细描述>
    //     * 
    //     * @param authType
    //     * @param parentId
    //     * @return [参数说明]
    //     * 
    //     * @return List<AuthItem> [返回类型说明]
    //     * @exception throws [异常类型] [异常说明]
    //     * @see [类、类#方法、类#成员]
    //     */
    //    public static List<AuthItem> getAuthItemListByAuthTypeAndParentIdFromSession(String authType, String parentId) {
    //        AssertUtils.notEmpty(parentId, "parentId is empty.");
    //        AssertUtils.notEmpty(authType, "authType is empty.");
    //        
    //        Map<String, AuthItem> authItemMapping = AuthContext.getContext().getAuthItemMapping();
    //        
    //        List<AuthItem> resList = new ArrayList<AuthItem>();
    //        MultiValueMap<String, AuthItemRef> authRefMulMap = getAuthRefMultiValueMapFromSession();
    //        for (String authIdTemp : authRefMulMap.keySet()) {
    //            if (!authItemMapping.containsKey(authIdTemp)) {
    //                continue;
    //            }
    //            
    //            AuthItem authItemTemp = authItemMapping.get(authIdTemp);
    //            if (parentId.equals(authItemTemp.get)
    //                    && authType.equals(authItemTemp.getAuthType())) {
    //                resList.add(authItemTemp);
    //            }
    //        }
    //        return resList;
    //    }
    
    //    /**
    //     * 获取当前拥有的永久类型权限项列表 <功能详细描述>
    //     * 
    //     * @return [参数说明]
    //     * 
    //     * @return List<AuthItem> [返回类型说明]
    //     * @exception throws [异常类型] [异常说明]
    //     * @see [类、类#方法、类#成员]
    //     */
    //    public static List<AuthItem> getPerpetualAuthItemListDependAuthRefOfSession() {
    //        Map<String, AuthItem> authItemMapping = AuthContext.getContext().getAuthItemMapping();
    //        
    //        List<AuthItem> authItemList = new ArrayList<AuthItem>();
    //        MultiValueMap<String, AuthItemRef> authRefMulMap = getAuthRefMultiValueMapFromSession();
    //        for (Entry<String, List<AuthItemRef>> entryTemp : authRefMulMap.entrySet()) {
    //            if (!authItemMapping.containsKey(entryTemp.getKey())) {
    //                continue;
    //            }
    //            
    //            AuthItem authItemTemp = authItemMapping.get(entryTemp.getKey());
    //            List<AuthItemRef> authItemRefListTemp = entryTemp.getValue();
    //            if (!CollectionUtils.isEmpty(authItemRefListTemp)) {
    //                for (AuthItemRef authItemRefTemp : authItemRefListTemp) {
    //                    authItemList.add(authItemTemp);
    //                }
    //            }
    //        }
    //        return authItemList;
    //    }
    
    /** HttpSession */
    public HttpSession getSession() {
        AssertUtils.isTrue(isInitSession, "请调用install方法初始化 HttpServletRequest");
        return session;
    }
    
    /**
     * 初始化(安装)会话容器<br/>
     * 1、提供给请求进入interceptor后调用该方法，将当前会话的request,response压入会话容器中以便后续判断权限 <功能详细描述>
     * 
     * @param request
     * @param response [参数说明]
     * 
     * @return void [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public void install(HttpServletRequest request, HttpServletResponse response) {
        this.request = request;
        this.response = response;
        if (this.request != null) {
            this.session = this.request.getSession();
        }
        this.isInitSession = true;
    }
    
    /**
     * 
     * 销毁容器中的数据，防止由于线程池造成的线程复用后，引用到不该引用的内容
     * 
     * @return void [返回类型说明]
     * @throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     * @version [版本号, 2016年9月29日]
     * @author rain
     */
    public void uninstall() {
        this.isInitSession = false;
        this.request = null;
        this.response = null;
        this.session = null;
        this.dataMap.clear();
    }
}
